package cxydmmszl.chapter09.t152;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;

/**
 * <li style="color: red;">Prob</li>
 * 能否完美地拼成矩形
 * <li style="color: green;">Desc</li>
 * 每条边不是平行于 X 轴就是平行于 Y 轴的矩形，可以用左下角和右上角的点来表示。
 * 比如 {1, 2, 3, 4}，表示的图形如下。<br/>
 * 给定一个 N 行4列的二维数组 matrix，表示 N 个每条边不是平行于 X 轴就是平行于 Y 轴的矩形。
 * 想知道所有的矩形能否组成一个大的完美矩形。完美矩形是指拼出的整体图案是矩形，既不缺任何块儿，
 * 也没有重合部分。
 * <br/><br/>[要求]<br/>
 * 时间复杂度为 O(n)，额外空间复杂度为 O(n)
 * <br/><br/>备注：<br/>
 * 1⩽N⩽10^5<br/>
 * 0⩽矩阵内的数⩽10^5
 * <li style="color: green;">Input</li>
 * 第一行一个整数 N，表示 matrix 的行数。
 * 接下来 N 行，每行 4 个整数分别表示矩形的左下角和右上角的点。
 * <li style="color: green;">Output</li>
 * 若可以拼成一个大的完美矩形，输出 "Yes", 否则输出 "No"。
 * <li style="color: blue;">Link</li> CD61
 *
 * @author habitplus
 * @since 2021-10-17 21:04
 */
public class Main {
    static final StreamTokenizer st =
            new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));

    static int nextInt() {
        try {
            st.nextToken();
            return (int) st.nval;
        } catch (IOException e) {
            throw new RuntimeException("input is invalid.");
        }
    }

    public static void main(String[] args) {
        int n = nextInt();
        int[][] arr = new int[n][4];

        for (int i = 0; i < n; i++) {
            arr[i][0] = nextInt();
            arr[i][1] = nextInt();
            arr[i][2] = nextInt();
            arr[i][3] = nextInt();
        }

        System.out.println(isPerfectRectangle(arr) ? "Yes" : "No");
    }

    public static boolean isPerfectRectangle(int[][] arr) {
        if (arr == null || arr.length == 0 || arr[0].length != 4) return false;

        /*
            面积法
         */
        // 记录两个相距最远的点
        int minLeft = Integer.MAX_VALUE;
        int maxRight = Integer.MIN_VALUE;
        int minDown = Integer.MAX_VALUE;
        int maxTop = Integer.MIN_VALUE;
        int area = 0;

        for (int i = 0; i < arr.length; i++) {
            minLeft = Math.min(minLeft, arr[i][0]);
            maxRight = Math.max(maxRight, arr[i][2]);
            minDown = Math.min(minDown, arr[i][1]);
            maxTop = Math.max(maxTop, arr[i][3]);
            area += (arr[i][2] - arr[i][0]) * (arr[i][3] - arr[i][1]);
        }

        return area == (maxRight - minLeft) * (maxTop - minDown);
    }

//    public static void main(String[] args) {
//        int n = nextInt();
//        int m = nextInt();
//        int[] arr1 = new int[n+m];
//        int[] arr2 = new int[m];
//        for (int i = 0; i < n; i++) {
//            arr1[i] = nextInt();
//        }
//
//        for (int i = 0; i < m; i++) {
//            arr2[i] = nextInt();
//        }
//
//        handle(arr1, n, arr2);
//        System.out.println(Arrays.toString(arr1));
//    }

    /**
     * 原地合并两个有序的数组，
     *
     * @param arr1 arr1 的空间足够大
     * @param arr2 有序的数组2
     * @param n    arr1 存放数据子数组的大小
     */
    static void handle(int[] arr1, int n, int[] arr2) {
        if (arr1 == null || arr2 == null
                || arr1.length < 1
                || arr2.length < 1
                || n < 0
                || arr1.length - arr2.length < n) {
            return;
        }
        int i = n - 1;
        int j = arr2.length - 1;
        int k = n + arr2.length - 1;

        while (i != -1 || j != -1) {
            if (i == -1) {
                arr1[k--] = arr2[j--];
            } else if (j == -1) {
                break;
            } else {
                if (arr1[i] > arr2[j]) {
                    arr1[k--] = arr1[i--];
                } else {
                    arr1[k--] = arr2[j--];
                }
            }
        }
    }
}
